<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>打开控制台查看结果</div>

<script>
    /* 
       Reflect拥有Object对象的内部方法，某些方法会同时在Object对象和Reflect对象上部署，也就是说Object对象上存在的方法，通过Reflect也可以访问到。
       
       Object对象上的某些方法会有些缺陷，例如：在Object.defineProperty上对一个不可写或不可枚举的属性进行setter或setter时会抛出错误，对于这个错误，我们需要tar catch去捕获，而Reflect.defineProperty则会抛出false来表示本次操作失败。
    */
//    const obj = { name : '东方不败' }
//    Object.defineProperty(obj,'age',{
//     value : 100,
//     writable : true,  // 只读
//     configurable : false  // 不可删除和修改
//    })
//    Object.defineProperty(obj,'age',{
//     get(){ return 200 }
//    })
//    console.log(obj.age); //  TypeError : Cannot redefine property: age
//    // 报错，不能重新定义属性

   /* Reflect */
   const obj2 = { name : '西方求败' }
   Object.defineProperty(obj2,'age',{
    value : 100,
    writable : true,  // 只读
    configurable : false  // 不可删除和修改
   })
   let status = Reflect.defineProperty(obj2,'age',{
    get(){ return }
   })
   console.log(status); //  false
   console.log(obj2.age); // 100
   // Reflect会抛出false表示此次操作失败

   /* Object的部分操作是命令式的 */
   let obj3 = {
    name : '东方不败',
    age : 100
   }
   console.log('name' in obj3);  // true
   console.log(delete obj3.age);  // true
   console.log(obj3);  // {name: '东方不败'}

   /* 而Reflect则会让这些操作变成函数式的 */
   let obj4 = {
    name : '西方求败',
    age : 100
   }
   console.log(Reflect.has(obj4,'name'));  // true
   console.log(Reflect.deleteProperty(obj4,'age')); // true
   console.log(obj4);  // {name: '西方求败'}

   /* 
      Reflect上存在的一些静态函数对应与ES2015之前的Object上可用的方法，尽管某些方法在行为上看起来相似，但它们之间常常存在着一些细微的差异。
      Reflect对象一共有13个静态方法，如下：
      https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/Comparing_Reflect_and_Object_methods
   */
  /* 
    1、Reflect.apply(target, thisArg, args)
    2、Reflect.construct(target, args)
    3、Reflect.get(target, name, receiver)
    4、Reflect.set(target, name, value, receiver)
    5、Reflect.defineProperty(target, name, desc)
    6、Reflect.deleteProperty(target, name)
    7、Reflect.has(target, name)
    8、Reflect.ownKeys(target)
    9、Reflect.isExtensible(target)
    10、Reflect.preventExtensions(target)
    11、Reflect.getOwnPropertyDescriptor(target, name)
    12、Reflect.getPrototypeOf(target)
    13、Reflect.setPrototypeOf(target, prototype)
  */

  /* 下面是关于上面一些方法的使用解释 */
  console.log('==========Reflect.get(target,name,receiver)=========');
  /* Reglect.get()有三个参数，分别是
     1、target  // 目标对象
     2、name    // 对象属性
     3、receiver  // 代理对象（可忽略）
  */
   /* 查找并返回target对象的name属性，如果该属性不存在则返回undefined */
   let o = {
    name : '东方',
    text : '不败'
  }
  console.log(Reflect.get(o,'name'));  // 东方

  console.log('===========Reflect.set(target, name, value, receiver)===========');
  /* 用于设置target对象的name属性等于value,如果修改成功返回true，失败返回false */
  let o2 = {
    name : '艺术概论',
  }
//   Object.defineProperty(o2,'price',{
//     configurable : false
//   })
  let back = Reflect.set(o2,'price',100)
  console.log(back); // true
  console.log(o2);  // {name: '艺术概论', price: 100}

  console.log('=========Reflect.has(obj, name)=========');
  /* 相当于Object里的in运算符，判断当前属性在目标对象内是否存在，true存在，false不存在
     如果Reflect.has的第一个参数不是对象会报错
  */
  let o3 = {
    name : '中国工艺美术史'
  }
  console.log('name' in o3);  // true
  console.log(Reflect.has(o3,'name')); // true

  console.log('=========Reflect.deleteProperty(obj, name)=========');
  /* 相当于Object的删除操作：delete obj.name,用于删除对象的属性 */
  let o4 = {
    book : '疾风劲草',
    text : '一臂之力'
  }
  delete o4.book
  console.log(o4);  // {text: '一臂之力'}
  Reflect.deleteProperty(o4,'text')
  console.log(o4);  // {}

  console.log('==========Reflect.construct(target, args)=======');
  /* 相当于new class(params)，这里的Reflect可以不用new来创建调用构造函数的方法 */
  function Person(name){
    this.name = name
  }
  // new 写法
  let onNew = new Person('东方')
  // Reflect.construct
  let onNew2 = Reflect.construct(Person,['不败'])
  /* Reflect.construct的第一个参数不是函数会报错 */

  console.log('===========Reflect.getPrototypeOf(obj)==========');
  /* 对应Object.getPrototypeOf(obj)，用于读取对象的__proto__属性 */
  let o5 = new String()
  // Object.getPrototypeOf()
  console.log(Object.getPrototypeOf(o5) == String.prototype); // true
  // Reflect.getPrototypeOf()
  console.log(Reflect.getPrototypeOf(o5) == String.prototype); // true


  console.log('===========Reflect.setPrototypeOf(obj, newProto)==========');
  /* 对应Object.setPrototypeOf(obj, newProto)，用于设置目标对象的原型（prototype) */
  let o6 = {}
  Reflect.setPrototypeOf(o6,Array.prototype)
  console.log(o6.length);  // 0

  
  console.log('===========Reflect.defineProperty(target, propertyKey, attributes)==========');
  /* 相当于Object.defineProperty，Reflect.defineProperty()用来定义对象的属性。 */
  let o7 = {
    name : '东方不败'
  }
  Reflect.defineProperty(o7,'age',{
    value : 100,
    configurable: true,
    enumerable : true,
    writable : true
  })
  console.log(o7);  // {name: '东方不败', age: 100}
  /* 如果Reflect.defineProperty()的第一个参数不是对象，会抛出错误。 */


  console.log('===========Reflect.getOwnPropertyDescriptor(target, propertyKey)==========');
  /* 对应Object.getOwnPropertyDescriptor，用来获得指定属性的描述对象 */
  let o8 = {
    name : '东方不败'
  }
  Reflect.defineProperty(o8,'age',{
    value : 100,
    configurable: true,
    enumerable : true,
    writable : true
  })
  let back8 = Reflect.getOwnPropertyDescriptor(o8,'age')
  console.log(back8);  // {value: 100, writable: true, enumerable: true, configurable: true}
 /* 如果Reflect.getOwnPropertyDescriptor()的第一个参数不是对象，会抛出错误。 */

 console.log('============Reflect.isExtensible (target)=========');
 /* 相当于Object.isExtensible，返回布尔值，表示当前对象是否扩展 */
 let o9 = {}
 let back9 = Reflect.isExtensible(o9)
 console.log(back9);  // true
 /* 如果参数不是对象会报错，非对象本来就是不可扩展的 */
 // console.log(Reflect.isExtensible(100));  // 报错

 console.log('============Reflect.preventExtensions(target)=========');
 /* 相当于Object.preventExtensions，可以让目标对象变为不可扩展状态，返回布尔值表示是否设置成功 */
 let b = {}
 let info =  Reflect.preventExtensions(b)
 console.log(info); // true
 console.log(Reflect.isExtensible(b)); // false
  /* 如果参数不是对象会报错 */

  console.log('============Reflect.ownKeys (target)===========');
  /* 用于返回目标对象的所有属性,包括Symbol */
  let address = Symbol.for('武汉')
  let b2 = {
    name : '东方不败',
    age : 100,
    [address] : '世界城广场'
  }
  let info2 = Reflect.ownKeys(b2)
  console.log(info2); // ['name', 'age', Symbol(武汉)]
  /* 如果参数不是对象会报错 */


  console.log('============Reflect.apply(func, thisArg, args)===========');
  /* 用于绑定this对象后执行给定函数
     通常情况下，如果要绑定一个函数的this对象，可以用fn.allpy(obj,args)的方式，但如果函数自己定义了自己的apply方法，就只能写成Function.prototype.apply.call(fn, obj, args)，使用Reflect对象可以简化这种操作
   */
  /* 
     Function.apply(obj,args)方法能接收两个参数  
     obj：这个对象将代替Function类里this对象
     args：这个是数组，它将作为参数传给Function
  */
 let arr = [1,2,3,4,5,6,7]
 // 旧写法
 let a = Math.min.apply(Math,arr)
 let a2 = Math.max.apply(Math,arr)
 let a3 = Object.prototype.toString.call(a)
 console.log(a);   // 1
 console.log(a2);  // 7
 console.log(a3);  // [object Number]

 // 新写法
 let a4 = Reflect.apply(Math.min,Math,arr)
 let a5 = Reflect.apply(Math.max,Math,arr)
 let a6 = Reflect.apply(Object.prototype.toString,a4,[])
 console.log(a4);  // 1
 console.log(a5);  // 7
 console.log(a6);  // [object Number]
 



</script>
</body> 
</html>